import java.io.*;

import java.util.ArrayList;
import java.util.LinkedList;

import org.xml.sax.*;
import org.xml.sax.helpers.*;

public class Training extends DefaultHandler {
  public static String LEXELT_TAG_ = "lexelt";
  public static String LEXELT_ITEM_TAG_ = "item";
  public static String CONTEXT_TAG_ = "context";
  public static String HEAD_TAG_ = "head";
  public static String ANSWER_TAG_ = "answer";
  public static String INSTANCE_TAG_ = "instance";
  public static String INSTANCE_ID_TAG_ = "id";
  public static String SENSE_TAG_ = "senseid";
  
  
  private final String trainFile_;
  
  private XMLParserState state_;
  private WordSenseCount wsc_;
  private CollocationFeature collocFeat_;
  private BagOfWordsFeature bowFeat_;

  public CollocationFeature getCollocFeat() {
    return collocFeat_;
  }
  
  public BagOfWordsFeature getBowFeat() {
    return bowFeat_;
  }

  public WordSenseCount getWordSenseCount() {
    return wsc_;
  }
  
  public Training(String file) {
    trainFile_ = file;
    state_ = new XMLParserState(true);
    wsc_ = new WordSenseCount();

    // Collocation feature.
    collocFeat_ = new CollocationFeature(XMLParserState.COLLOCATION_FEAT_LENGTH_, wsc_);

    // Bag of Words feature.
    bowFeat_ = new BagOfWordsFeature(wsc_);

    parseTrainFile();
  }

  public void parseTrainFile() {
    String tmpFile = "tmp.xml";
    try {
      FileWriter writer = new FileWriter(tmpFile);
      FileReader reader = new FileReader(trainFile_);
      XMLReader xmlr = XMLReaderFactory.createXMLReader();
      xmlr.setContentHandler(this);
      xmlr.setErrorHandler(this);

      BufferedReader br = new BufferedReader(reader);
      WSD.formatXMLfile(br, writer);
      reader.close();
      reader = new FileReader(tmpFile);

      // Parse the intermediate XML file.
      xmlr.parse(new InputSource(reader));
    } catch (IOException ex) {
      throw new RuntimeException(ex);
    } catch (SAXParseException spe) {
      StringBuffer sb = new StringBuffer(spe.toString());
      sb.append("\n  Line number: " + spe.getLineNumber());
      sb.append("\nColumn number: " + spe.getColumnNumber());
      sb.append("\n Public ID: " + spe.getPublicId());
      sb.append("\n System ID: " + spe.getSystemId() + "\n");
      System.err.println(sb.toString());
    } catch (SAXException se) {
      System.out.println("loadDOM threw " + se);
      se.printStackTrace(System.out);
    }
  }

  @Override
  public void startDocument() throws SAXException {
  }

  @Override
  public void startElement(String uri, String name, String qName,
      Attributes atts) {
    if (qName.equals(LEXELT_TAG_)) {
      state_.setLexelt(atts.getValue(LEXELT_ITEM_TAG_));
    } else if (qName.equals(HEAD_TAG_)) {
      state_.startHeadTag();
    } else if (qName.equals(ANSWER_TAG_)) {
      state_.addSense(atts.getValue(SENSE_TAG_));
    } else if (qName.equals(INSTANCE_TAG_)) {
      state_.resetForInstance(atts.getValue(INSTANCE_ID_TAG_));
    }
  }

  @Override
  public void endElement(String uri, String name, String qName) {
    if (qName.equals(HEAD_TAG_)) {
      state_.endHeadTag();
    } else if (qName.equals(INSTANCE_TAG_)) {
      collocFeat_.handleInstance(state_);
      bowFeat_.handleInstance(state_);
      
      for (String sense: state_.getSensesForInstance()) {
        wsc_.addSenseForWord(state_.getLexelt(), sense);
      }
    } else if (qName.equals(LEXELT_TAG_)) {
      bowFeat_.handleLexelt(state_);
      wsc_.processLexelt(state_.getLexelt());
    }
  }

  @Override
  public void characters(char ch[], int start, int length) {
    String line = new String(ch, start, length);

    // Handle BagOfWordsFeature
    bowFeat_.handleTrainCharacters(line, state_);
    
    // Handle CollocationFeature
    collocFeat_.handleCharacters(line, state_);
  }

  @Override
  public void endDocument() throws SAXException {
    // Set the most frequent words as features.
  }
}
